﻿using NPOI.SS.Formula.Functions;
using NPOI.SS.UserModel;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Metadata.Ecma335;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;

namespace MDT.LifeSewagePlatform.Conmmon
{
    public class ExcelHelper : IExcelHelper
    {
        Dictionary<string, int> DicColName { get; set; }
        int StartRow = 0;

        public ExcelHelper()
        {
            DicColName = new Dictionary<string, int>();
            _sheet = null;
        }
        /// <summary>
        /// 读取excel 映射成对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="fileName">文件位置</param>
        /// <param name="sheetName">excel 名称</param>
        /// <param name="isFirstRowColumn">解析类名称</param>
        /// <returns></returns>
        public async Task<List<T>> GetExcelList<T>(Stream stream, string sheetName = null, bool isFirstRowColumn = true)
        {
           
                List<T> data = new List<T>();
                Type dataType = typeof(T);
                if (stream != null)
                {
                    IWorkbook workbook = WorkbookFactory.Create(stream);

                    if (!string.IsNullOrEmpty(sheetName))
                    {
                        _sheet = workbook.GetSheet(sheetName);
                        if (_sheet == null)
                        {
                            _sheet = workbook.GetSheetAt(0);
                        }
                    }
                    else
                    {
                        _sheet = workbook.GetSheetAt(0);
                    }
                    if (_sheet != null)
                    {
                        
                         await ReadHead(isFirstRowColumn);
                         return await ReadBody<T>();

                    }
                }
                return null;
        }
        private ISheet _sheet;
        public async Task<List<T>> GetExcelList<T>()
        {
           
                if (_sheet == null)
                {
                    return null;
                }

                return await ReadBody<T>();
           
        }

        public async Task ReadHead(bool isFirstRowColumn)
        {
            await Task.Run(() =>
           {
                #region 解析首行获取列名称
                IRow firstRow = _sheet.GetRow(0);
               int cellCount = firstRow.LastCellNum;

               if (isFirstRowColumn)
               {
                   for (int i = firstRow.FirstCellNum; i < cellCount; ++i)
                   {
                       ICell cell = firstRow.GetCell(i);
                       if (cell != null)
                       {
                           string cellValue = cell.StringCellValue;//读取string类型的值
                            if (cellValue != null)
                           {
                               DicColName.Add(cellValue, i);
                           }
                       }
                   }
                   StartRow = _sheet.FirstRowNum + 1;
               }
               else
               {
                   StartRow = _sheet.FirstRowNum;
               }
                #endregion
            });


        }

        public async Task<List<T>> ReadBody<T>()
        {
          return await Task.Run(() =>
            {
                List<T> data = new List<T>();
                Type dataType = typeof(T);
                for (int i = StartRow; i <= _sheet.LastRowNum; ++i)
                {
                    IRow row = _sheet.GetRow(i);
                    object obj = Activator.CreateInstance(dataType);
                    if (row == null) continue; //没有数据的行默认是null　　　　　　　
                    foreach (var item in dataType.GetProperties())
                    {
                        if (DicColName.ContainsKey(item.GetColName()))
                        {
                            int index = DicColName[item.GetColName()];
                            if (row.FirstCellNum<=index &&row.LastCellNum > index)
                            {
                               
                                switch (row.GetCell(index).CellType)
                                {
                                    case CellType.Numeric:
                                        string Strvalue = row.GetCell(index).NumericCellValue.ToString();
                                        if (string.IsNullOrEmpty(Strvalue) &&
                                            row.LastCellNum < index + 1 &&
                                            string.IsNullOrEmpty(row.GetCell(index).NumericCellValue.ToString()))
                                        {
                                            return data;
                                        }
                                        if (item.PropertyType == typeof(Int32))
                                        {
                                            int.TryParse(Strvalue, out int value);
                                            item.SetValue(obj,value);
                                        }
                                        else if (item.PropertyType == typeof(double))
                                        {
                                            double.TryParse(Strvalue, out double value);
                                            item.SetValue(obj,Math.Round(value,2));
                                        }
                                        else if (item.PropertyType == typeof(string))
                                        {
                                            item.SetValue(obj,Strvalue);
                                        }

                                        break;
                                    case CellType.String:
                                        string str=row.GetCell(index).StringCellValue;
                                       
                                        if (item.PropertyType==typeof(DateTime))
                                        {
                                            DateTime.TryParse(str,out DateTime res);
                                            item.SetValue(obj,res);
                                        }
                                        else
                                        {
                                             item.SetValue(obj,str);
                                        }
                                        break;
                                    case CellType.Blank:

                                        return data;
                                    case CellType.Formula:
                                         Strvalue = row.GetCell(index).NumericCellValue.ToString();
                                        if (string.IsNullOrEmpty(Strvalue) &&
                                            row.LastCellNum < index + 1 &&
                                            string.IsNullOrEmpty(row.GetCell(index).NumericCellValue.ToString()))
                                        {
                                            return data;
                                        }
                                        if (item.PropertyType == typeof(Int32))
                                        {
                                            int.TryParse(Strvalue, out int value);
                                            item.SetValue(obj, value);
                                        }
                                        else if (item.PropertyType == typeof(double))
                                        {
                                            double.TryParse(Strvalue, out double value);
                                            item.SetValue(obj,Math.Round(value,2));
                                        }
                                        else if (item.PropertyType == typeof(string))
                                        {
                                            item.SetValue(obj, Strvalue);
                                        }
                                        break;
                                    case CellType.Unknown:
                                        break;
                                }
                            }
                            else
                            {
                             return data;
                            }
                        }
                    }
                    data.Add((T)obj);
                }
                return data;
            });

        }
    }
}